#include "Raster.h"
#include <assert.h>

Raster::Raster(int w, int h)
{
	width = w; 
	height = h;

	screen = new STImage(width, height);
	screen2 = new STImage(width, height);
	stamps = new int[width*height/STAMP_SIZE/STAMP_SIZE];
	analyze_buffer = new int[width*height];
	analyze_buffer2 = new int[width*height];
	bit_mask_buffer = new bit[width*height*MULTI_SAMPLE_RATE];
	memset(bit_mask_buffer, 0, width*height*MULTI_SAMPLE_RATE*sizeof(bit));
	clearAnalyzeBuffer();

	bound_samples = 0;
	bound_bit_masks = 0;

	samples_per_stamp = 0;
	bit_masks_per_stamp = 0;

	resetAnalyzeData();
	initColor();
	initSamples();
}

void Raster::initColor()
{	
	// generate the step, ignore the parts 
	int step = 255/(NUM_COLOR/3);

	for (int i = 0; i < NUM_COLOR/3; i++)
	{
		color_list[i] =  STImage::Pixel(0, i*step, 255, ALPHA);		// Blue to green
		color_list[(NUM_COLOR/3)*1+i] = STImage::Pixel(i*step, 255, 0, ALPHA);		// green to yellow 
		color_list[(NUM_COLOR/3)*2+i] = STImage::Pixel(255, 255-i*step, 0, ALPHA);		// yellow to red 
	}

	//// generate the step, ignore the parts 
	//// 1, 1, 1, 2 rule
	//int step = 255/(NUM_COLOR/5);

	//for (int i = 0; i < NUM_COLOR/5; i++)
	//{
	//	color_list[i] =  STImage::Pixel(0, i*step, 255, ALPHA);		// Blue to blue green
	//	color_list[(NUM_COLOR/5)+i] = STImage::Pixel(0, 255, 255-i*step, ALPHA);		// blue green to green
	//	color_list[(NUM_COLOR/5)*2+i] = STImage::Pixel(i*step, 255, 0, ALPHA);		// green to yellow 
	//	color_list[(NUM_COLOR/5)*3+i] = STImage::Pixel(255, 255-i*step/2, 0, ALPHA);		// yellow to red 
	//	color_list[(NUM_COLOR/5)*4+i] = STImage::Pixel(255, 125-i*step/2, 0, ALPHA);
	//}
}

void Raster::initSamples()
{
	// samples can only be 1, 4, 16, 32 
	// it ranges from 0.0 to 1.0
	double rate = (double)MULTI_SAMPLE_RATE;
	float n = sqrt(rate);
	float step = 1/(n+1.0f);

	for (int y = 0; y < n; y++)
		for (int x = 0; x < n; x++)
		{
			STVector3 v(step*(x+1), step*(y+1), 0);
			int index = (int)(y*n+x);
			offset_pattern[index] = v;
		}
}

void Raster::resetAnalyzeData()
{
	data.clear();

	memset(areas, 0, NUM_AREA*sizeof(Area));
	//areas[0].area = 0.2;
	/*for (int i = 1; i < 10; i++)
		areas[i].area = areas[i-1].area + 0.2;*/
	/*for (int i = 0; i < NUM_AREA; i++)
		areas[i].area = areas[i-1].area+1;*/
	areas[NUM_AREA-1].area = 0.0f;
}

void Raster::clearAnalyzeBuffer()
{
	memset(analyze_buffer, 0, width*height*sizeof(int));
	memset(analyze_buffer2, 0, width*height*sizeof(int));
}

void Raster::clearBitMaskBuffer()
{
	memset(bit_mask_buffer, 0, width*height*MULTI_SAMPLE_RATE*sizeof(bit));
}

void Raster::init(GLfloat* v, GLfloat* n, GLfloat* c, GLuint *i, GLuint* p, int nv, int ni, int np)
{
	vertices = v;
	normals = n;
	colors = c;
	indices = i;
	patches = p;
	numIndices = ni;
	numPatches = np;
}

Raster::~Raster()
{
	if (screen != 0)
		delete screen;
	if (screen2 != 0)
		delete screen2;
	if (analyze_buffer != 0)
		delete analyze_buffer;
	if (bound_samples != 0)
		delete bound_samples;
	if (samples_per_stamp != 0)
		delete samples_per_stamp;
	if (bound_bit_masks != 0)
		delete bound_bit_masks;
	if (bit_masks_per_stamp != 0)
		delete bit_masks_per_stamp;
	if (bit_mask_buffer != 0)
		delete bit_mask_buffer;
}

void Raster::rasterTriangle(int index, int pid)
{
	// for all triangles 
	int i = index*9;		// 9 elements per triangle

	// three input vertices
	GLdouble ov1[3] = {vertices[i], vertices[i+1], vertices[i+2]};
	GLdouble ov2[3] = {vertices[i+3], vertices[i+4], vertices[i+5]};
	GLdouble ov3[3] = {vertices[i+6], vertices[i+7], vertices[i+8]};

	/*printf("input point %f %f %f \n", ov1[0], ov1[1], ov1[2]);
	printf("input point %f %f %f \n", ov2[0], ov2[1], ov2[2]);
	printf("input point %f %f %f \n", ov3[0], ov3[1], ov3[2]);*/

	// convert to screen space
	GLdouble sv1[3];
	GLdouble sv2[3];
	GLdouble sv3[3];
	gluProject(ov1[0], ov1[1], ov1[2], m, p, v, &sv1[0], &sv1[1], &sv1[2]);
	gluProject(ov2[0], ov2[1], ov2[2], m, p, v, &sv2[0], &sv2[1], &sv2[2]);
	gluProject(ov3[0], ov3[1], ov3[2], m, p, v, &sv3[0], &sv3[1], &sv3[2]);

	/*printf("new screen point %f %f %f \n", sv1[0], sv1[1], sv1[2]);
	printf("new screen point %f %f %f \n", sv2[0], sv2[1], sv2[2]);
	printf("new screen point %f %f %f \n", sv3[0], sv3[1], sv3[2]);*/
	
	STVector3 v0(sv1[0], sv1[1], sv1[2]);
	STVector3 v1(sv2[0], sv2[1], sv2[2]);
	STVector3 v2(sv3[0], sv3[1], sv3[2]);

	// setup();

	// back face cull
	if (!facing(v0, v1, v2))
	{
		// back face detected in patch 
		backfacingPatch.push_back(pid);
		return;
	}

	bound(v0, v1, v2);

	// analyze, don't count back facing triangle
	MetaData d;
	d.samples_bounded = num_bound_samples;
	d.boundingbox_size = boundbox_size;
	d.area = triagnleArea(v0, v1, v2);
	
	// round 1
	float num_hit = 0.0;
	float num_miss = 0.0;

	for (int i = 0; i < num_bound_samples; i++)
	{
		// ignore any point outside screen.
		STVector3* s = bound_samples;
		if (s[i].x > width -1 || s[i].y > height - 1 || s[i].x < 0 || s[i].y < 0)
			return;

		STVector2 location = screenIndex(s[i].x, s[i].y);
		updateTest(location.x, location.y, analyze_buffer);
		
		if (test(v0, v1, v2, s[i]))
		{
			num_hit++;
			// check the hit with back facing patch id 
			if (count(backfacingPatch.begin(), backfacingPatch.end(), pid) != 0)
			{
				screen2->SetPixel(location.x, location.y, STImage::Pixel(0,255,0));
			}
		}
		else 
		{
			num_miss++;
		}
	}

	d.hit_rate = num_hit/(num_hit+num_miss);

	// round 2
	
	num_hit = 0.0;
	num_miss = 0.0;

	filter();

	d.num_filtered = num_bound_samples - filtered_samples.size();

	for (int i = 0; i < filtered_samples.size(); i++)
	{
		// ignore any point outside screen.
		if (filtered_samples[i].x > width -1 || filtered_samples[i].y > height - 1 || filtered_samples[i].x < 0 || filtered_samples[i].y < 0)
			return;

		STVector2 location = screenIndex(filtered_samples[i].x, filtered_samples[i].y);
		updateTest(location.x, location.y, analyze_buffer2);
		
		if (test(v0, v1, v2, filtered_samples[i]))
		{
			num_hit++;
			updateBitMask(filtered_samples[i].x, filtered_samples[i].y);
		}
		else 
		{
			num_miss++;
		}
	}
	
	if (num_hit == 0.0f && num_miss == 0.0f)
		d.hit_rate2 = 1.0f;
	else 
		d.hit_rate2 = num_hit/(num_hit+num_miss);

	d.patch_id = pid;
	data.push_back(d);
}

void Raster::executionTime(GLdouble* model, GLint* view, GLdouble* project)
{
	STVector3 v0(0.17534, 0.9876, 0.1234);
	STVector3 v1(0.877534, 0.5876, 0.3234);
	STVector3 v2(0.27534, 0.8876, 0.4234);
	STVector3 p(0.33534, 0.6576, 0.1034);

	DWORD ss, ee, time_setup, time_bound, time_test, time_test2, time_filter;

	ss = timeGetTime();
	for (int index = 0; index < 131072; index++)
	{
		facing(v0, v1, v2);
	}
	ee = timeGetTime();

	time_setup = ee-ss;

	ss = timeGetTime();
	for (int index = 0; index < 131072; index++)
	{
		exeBound(v0, v1, v2);
	}
	ee = timeGetTime();

	time_bound = ee-ss;

	ss = timeGetTime();
	for (int index = 0; index < 8454272; index++)
	{
		exeTest(v0, v1, v2, p);
	}
	ee = timeGetTime();
	time_test = ee - ss;

	ss = timeGetTime();
	for (int index = 0; index < 4784898; index++)
	{
		exeTest(v0, v1, v2, p);
	}
	ee = timeGetTime();
	time_test2 = ee - ss;

	ss = timeGetTime();
	for (int index = 0; index < 131072; index++)
	{
		for (int j = 0; j < 64; j++)
		{
			bit b = bit_mask_buffer[j];
			b++;
		}
	}
	ee = timeGetTime();

	time_filter = ee -ss;

	printf("%d\t%d\t%d\t%d\t%d\n", time_setup, time_bound, time_test, time_test2, time_filter);
	
}

void Raster::exeSetup(STVector3 &A, STVector3 &B, STVector3 &C)
{
	
}

void Raster::exeBound(STVector3 &v0, STVector3 &v1, STVector3 &v2)
{
	float minx, maxx, maxy, miny;	// left, right, up, down
	minx = v0.x; maxx = v0.x;
	miny = v0.y; maxy = v0.y;

	STVector3 v[3] = {v0, v1, v2};
	for (int i = 0; i < 3; i++)
	{
		minx = MIN(minx, v[i].x);
		miny = MIN(miny, v[i].y);
		maxx = MAX(maxx, v[i].x);
		maxy = MAX(maxy, v[i].y);
	}

	int l = floor(minx/STAMP_SIZE);
	int r = ceil(maxx/STAMP_SIZE);
	int d = floor(miny/STAMP_SIZE);
	int u = ceil(maxy/STAMP_SIZE);
}

void Raster::exeTest(STVector3 &A, STVector3 &B, STVector3 &C, STVector3 &P)
{
	// Compute vectors        
	STVector3 v0 = C - A;
	STVector3 v1 = B - A;
	STVector3 v2 = P - A;

	// Compute dot products
	float dot00 = STVector3::Dot(v0, v0);
	float dot01 = STVector3::Dot(v0, v1);
	float dot02 = STVector3::Dot(v0, v2);
	float dot11 = STVector3::Dot(v1, v1);
	float dot12 = STVector3::Dot(v1, v2);

	// Compute barycentric coordinates
	float invDenom = 1 / (float)(dot00 * dot11 - dot01 * dot01);
	float u = (dot11 * dot02 - dot01 * dot12) * invDenom;
	float v = (dot00 * dot12 - dot01 * dot02) * invDenom;

	// Check if point is in triangle
	bool b = (u > 0) && (v > 0) && (u + v < 1);
}

void Raster::raster(GLdouble* model, GLint* view, GLdouble* project)
{
	executionTime(model, view, project);
	clearAnalyzeBuffer();
	clearBitMaskBuffer();
	resetAnalyzeData();

	m = model;
	v = view;
	p = project;

	int index = 0;
	// for all patches
	for (int i = 0; i < numPatches; i++)
	{
		// for all faces in patches
		for (int j = 0; j < patches[i]; j++)
		{
			rasterTriangle(index, i);
			index++;
		}

		//reset patch
		clearBitMaskBuffer();
	}

	//::test code for indices locality, results in 8 triangles share one index pattern. 
	//for (int i = 0; i < numIndices; i+=3)
	//	printf("indices %i %i %i \n", indices[i], indices[i+1], indices[i+2]);
	generateGraph();
	saveAnalyze();
}

void Raster::raster2(GLdouble* model, GLint* view, GLdouble* project)
{
	clearAnalyzeBuffer();
	clearBitMaskBuffer();
	resetAnalyzeData();

	m = model;
	v = view;
	p = project;

	int counter = 0;
	int patch_size = TESS_STEP;
	for (int i = 0; i < nSub; i++)
	{
		patch_size*= TESS_STEP;
	}

	// for all triangles 
	for (int i = 0; i < numIndices/3; i++)
	{
		rasterTriangle(i, (int)i/patch_size);
		counter++;
		//reset patch
		if (counter >= patch_size)
		{
			clearBitMaskBuffer();
			counter = 0;
		}
	}

	//::test code for indices locality, results in 8 triangles share one index pattern. 
	//for (int i = 0; i < numIndices; i+=3)
	//	printf("indices %i %i %i \n", indices[i], indices[i+1], indices[i+2]);
	generateGraph();
	saveAnalyze();
}

void Raster::updateBitMask(float screen_x, float screen_y)
{
	float offset_x = screen_x - floor(screen_x);
	float offset_y = screen_y - floor(screen_y);

	int n = -1;
	for (int i = 0; i < MULTI_SAMPLE_RATE; i++)
	{
		if (abs(offset_pattern[i].x  - offset_x) < EPSILON && 
			abs(offset_pattern[i].y - offset_y) < EPSILON)
		{
			n = i;
			break;
		}
	}

	assert(n != -1);

	int index = (floor(screen_y)*width + floor(screen_x))*MULTI_SAMPLE_RATE + n;
	bit_mask_buffer[index] = true;
}

void Raster::bound(STVector3 &v0, STVector3 &v1, STVector3 &v2)
{
	float minx, maxx, maxy, miny;	// left, right, up, down
	minx = v0.x; maxx = v0.x;
	miny = v0.y; maxy = v0.y;

	STVector3 v[3] = {v0, v1, v2};
	for (int i = 0; i < 3; i++)
	{
		minx = MIN(minx, v[i].x);
		miny = MIN(miny, v[i].y);
		maxx = MAX(maxx, v[i].x);
		maxy = MAX(maxy, v[i].y);
	}

	int l = floor(minx/STAMP_SIZE);
	int r = ceil(maxx/STAMP_SIZE);
	int d = floor(miny/STAMP_SIZE);
	int u = ceil(maxy/STAMP_SIZE);

	// cilp the samples outside the screen
	// bug full size bug
	if (l < 0) l = 0;
	if (r > width/STAMP_SIZE -1) r = width/STAMP_SIZE;
	if (d < 0) d = 0;
	if (u > height/STAMP_SIZE -1) u = height/STAMP_SIZE;

	if (bound_samples != 0)
		delete bound_samples;
	num_bound_samples = (r-l)*(u-d)*STAMP_SIZE*STAMP_SIZE*MULTI_SAMPLE_RATE;
	boundbox_size = (r-l)*(u-d)*STAMP_SIZE*STAMP_SIZE;
	bound_samples = new STVector3[num_bound_samples];
	int block_size = STAMP_SIZE*STAMP_SIZE*MULTI_SAMPLE_RATE;

	// bit mask should have the same kind of sequential pattern.
	// per stamp setup 
	for (int y = 0; y < (u-d); y++)
		for (int x = 0; x < (r-l); x++)
		{
 			STVector3* s = stampSamples(l+x, d+y);
			for (int k =0; k < block_size; k++)
			{
				bound_samples[(y*(r-l)+x)*block_size + k] = s[k]; 
			}
		}

	//must have the same pattern with bound samples, since it is a filter for bound samples. 
	if (bound_bit_masks != 0)
		delete bound_bit_masks;
	bound_bit_masks =  new bit[num_bound_samples];
	for (int y = 0; y< (u-d); y++)
		for (int x = 0; x < (r-l); x++)
		{
			bit* b = stampBitMasks(l+x, d+y);
			for (int k =0; k < block_size; k++)
			{
				bound_bit_masks[(y*(r-l)+x)*block_size + k] = b[k]; 
			}
		}	
}

bool Raster::sampleInScreen(float x, float y)
{
	int pixel_x = floor(x);
	int pixel_y = floor(y);
	return  ( pixel_x > width - 1 || pixel_x < 0 || pixel_y > height -1 || pixel_y < 0);
}

void Raster::setup()
{
		
}

int Raster::filter()
{
	filtered_samples.clear();
	for (int i = 0; i < num_bound_samples; i++)
	{
		if (bound_bit_masks[i] == false)
		{
			filtered_samples.push_back(bound_samples[i]);
		}
	}

	return filtered_samples.size();
}

// x, y is stamp location 
STVector3* Raster::stampSamples(int base_x, int base_y)
{
	if (samples_per_stamp != 0)
		delete samples_per_stamp;

	samples_per_stamp = new STVector3[STAMP_SIZE*STAMP_SIZE*MULTI_SAMPLE_RATE];
	for (int y = 0; y < STAMP_SIZE; y++)
		for (int x = 0; x < STAMP_SIZE; x++)
		{
			STVector3 base(base_x*STAMP_SIZE+x, base_y*STAMP_SIZE+y, 0); // base screen space
			for (int k = 0; k < MULTI_SAMPLE_RATE; k++)
				samples_per_stamp[(y*STAMP_SIZE+x)*MULTI_SAMPLE_RATE+k] = base+offset_pattern[k];
		}

	return samples_per_stamp;
}

// x, y is stamp location 
bit* Raster::stampBitMasks(int base_x, int base_y)
{
	if (bit_masks_per_stamp != 0)
		delete bit_masks_per_stamp;

	bit_masks_per_stamp = new bit[STAMP_SIZE*STAMP_SIZE*MULTI_SAMPLE_RATE];
	for (int y = 0; y < STAMP_SIZE; y++)
		for (int x = 0; x < STAMP_SIZE; x++)
		{
			int screen_x =  base_x*STAMP_SIZE+x;
			int screen_y = base_y*STAMP_SIZE+y;
			for (int k = 0; k < MULTI_SAMPLE_RATE; k++)
				bit_masks_per_stamp[(y*STAMP_SIZE+x)*MULTI_SAMPLE_RATE+k] = bit_mask_buffer[(screen_y*width+screen_x)*MULTI_SAMPLE_RATE+k];
		}

	return bit_masks_per_stamp;
}

void Raster::updateTest(int x, int y, int* buffer)
{
	buffer[y*width+x]++;
}

STVector2 Raster::screenIndex(float x, float y)
{
	return STVector2(floor(x),floor(y));
}

bool Raster::facing(STVector3 &v0, STVector3 &v1, STVector3 &v2)
{
	STVector3 normal = STVector3::Cross((v1-v0), (v2-v1));
	return normal.z > EPSILON ? true : false;
}

bool Raster::test(STVector3 &A, STVector3 &B, STVector3 &C, STVector3 &P)
{
	// Compute vectors        
		STVector3 v0 = C - A;
		STVector3 v1 = B - A;
		STVector3 v2 = P - A;

		// Compute dot products
		float dot00 = STVector3::Dot(v0, v0);
		float dot01 = STVector3::Dot(v0, v1);
		float dot02 = STVector3::Dot(v0, v2);
		float dot11 = STVector3::Dot(v1, v1);
		float dot12 = STVector3::Dot(v1, v2);

		// Compute barycentric coordinates
		float invDenom = 1 / (float)(dot00 * dot11 - dot01 * dot01);
		float u = (dot11 * dot02 - dot01 * dot12) * invDenom;
		float v = (dot00 * dot12 - dot01 * dot02) * invDenom;

		// Check if point is in triangle
		return (u > 0) && (v > 0) && (u + v < 1);
}

// return the screen space area
float Raster::triagnleArea(STVector3 &v0, STVector3 &v1, STVector3 &v2)
{
	return abs((v1.x*v0.y-v0.x*v1.y)+(v2.x*v1.y-v1.x*v2.y)+(v0.x*v2.y-v2.x*v0.y))/2;
}

void Raster::drawBackPatch()
{
	char filename1[150];
	int rate = MULTI_SAMPLE_RATE;
	int size = STAMP_SIZE;
	sprintf(filename1, "%s_RASTE_sub_%i_camPos_%i_mul_%i_stp_%i_3.png", model_name.c_str(), nSub, camPos, rate, size);
	screen2->Save(filename1);
}

void Raster::generateGraph()
{
	
	char filename0[150];
	sprintf(filename0, "%s_RASTE_Color_Pattern.png", model_name.c_str());

	// color pattern 
	STImage colorStyle(250, 20);
	
	int step = 250/NUM_COLOR;
	for (int i = 0; i < 250; i++)
	{
			for (int j = 0; j < 20; j++)
			{
				if ((int)(i/step) == 0)
					colorStyle.SetPixel(i, j, BACK_GROUND_COLOR);
				else 
					colorStyle.SetPixel(i, j, color_list[i/step]);	
			}
	}
	colorStyle.Save(filename0);


	P = 0;
	a = 0;

	for (int y = 0; y< height; y++)
		for (int x = 0; x < width; x++)
		{
			STImage::Pixel color;
			int index = y*width+x;

			if (analyze_buffer[index] != 0)
			{
				P+=analyze_buffer[index]/MULTI_SAMPLE_RATE;
				a++;
			}

			if (analyze_buffer[index] == 0)
				color = BACK_GROUND_COLOR;
			else if (analyze_buffer[index]/MULTI_SAMPLE_RATE < NUM_COLOR)
			 color = color_list[analyze_buffer[index]/MULTI_SAMPLE_RATE];
			else
				color = color_list[NUM_COLOR-1]; 	

			/*if (analyze_buffer[index] > 4)
			{
				printf("the sample at %i %i has %i times xx \n", x, y, analyze_buffer[index]);
			}*/

			screen->SetPixel(x, y, color);
		}

	char filename1[150];
	int rate = MULTI_SAMPLE_RATE;
	int size = STAMP_SIZE;
	sprintf(filename1, "%s_RASTE_sub_%i_camPos_%i_mul_%i_stp_%i_1.png", model_name.c_str(), nSub, camPos, rate, size);
	screen->Save(filename1);
	

	P2 = 0;
	for (int y = 0; y< height; y++)
		for (int x = 0; x < width; x++)
		{
			STImage::Pixel color;
			int index = y*width+x;

			if (analyze_buffer2[index]!=0)
			{
				P2+=analyze_buffer2[index]/MULTI_SAMPLE_RATE;
			}

			if (analyze_buffer2[index] == 0)
				color = BACK_GROUND_COLOR;
			else if (analyze_buffer2[index]/MULTI_SAMPLE_RATE < NUM_COLOR)
			 color = color_list[analyze_buffer2[index]/MULTI_SAMPLE_RATE];
			else
				color = color_list[NUM_COLOR-1]; 	

			screen->SetPixel(x, y, color);
		}

	char filename2[150];
	sprintf(filename2, "%s_RASTE_sub_%i_camPos_%i_mul_%i_stp_%i_2.png",  model_name.c_str(), nSub, camPos ,rate, size);
	screen->Save(filename2);

	drawBackPatch();
}

void Raster::saveGLScreen(char* name)
{
	screen->Read(0,0);
	screen->Save(name);
}

void Raster::saveAnalyze()
{
	char filename1[150];
	int rate = MULTI_SAMPLE_RATE;
	int size = STAMP_SIZE;
	sprintf(filename1, "%s_DATA_sub_%i_camPos_%i_mul_%i_stp_%i_1.txt",  model_name.c_str(), nSub, camPos, rate, size);
	FILE* output = fopen(filename1, "w");
	fprintf(output, "%s\t%s\t%s\t%s\t%s\t%s\n", "area", "samples", "bbox_size", "rate", "rate2", "filtered");
	for (size_t i = 0; i < data.size(); i++)
	{
	/*	STVector3 v0 = data[i].v0;
		STVector3 v1 = data[i].v1;
		STVector3 v2 = data[i].v2;*/

		// fprintf(output, "%f %f %f %f %f %f \n", v0.x, v0.y, v1.x, v1.y, v2.x, v2.y);
		fprintf(output, "%f\t%f\t%f\t%f\t%f\t%i\n", data[i].area, data[i].samples_bounded, data[i].boundingbox_size, data[i].hit_rate, data[i].hit_rate2, data[i].num_filtered);
	}
	fclose(output);

	int num_patches = 1;
	int num_back = 0;
	int id = data[0].patch_id;
	for (size_t i = 0; i < data.size(); i++)
	{
		if (id != data[i].patch_id)
		{
			num_patches++;
			if (count(backfacingPatch.begin(), backfacingPatch.end(), id) != 0)
			{
				num_back++;
			}

			id = data[i].patch_id;
		}
	}

	char filename2[150];
	sprintf(filename2, "%s_DATA_sub_%i_camPos_%i_mul_%i_stp_%i_2.txt",  model_name.c_str(), nSub, camPos, rate, size);
	FILE* output2 = fopen(filename2, "w");
	for (size_t i = 0; i < data.size(); i++)
	{
		for (int j = 0; j < NUM_AREA; j++)
		{
			/*if (data[i].area < areas[j].area)*/
			//{
				areas[j].area+=data[i].area;
				areas[j].num++;
				areas[j].data.hit_rate += data[i].hit_rate;
				areas[j].data.hit_rate2 += data[i].hit_rate2;
				areas[j].data.num_filtered += data[i].num_filtered;
				areas[j].data.samples_bounded += data[i].samples_bounded;
				areas[j].data.boundingbox_size += data[i].boundingbox_size;
				break;
			//}
		}		
	}
	
	fprintf(output2, "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n", "area", "num", "num_patch", "num_back", "ave_rate", "avg_rate2", "ave_bbox_size", "avg_flt", "P", "P2", "a");
	for (int i = 0; i < NUM_AREA; i++)
		fprintf(output2, "%f\t%i\t%i\t%i\t%f\t%f\t%f\t%f\t%i\t%i\t%i\n", 
		areas[i].area/areas[i].num, 
		areas[i].num, 
		num_patches,
		num_back,
		areas[i].data.hit_rate/areas[i].num, 
		areas[i].data.hit_rate2/areas[i].num, 
		areas[i].data.boundingbox_size/areas[i].num,
		(float)areas[i].data.num_filtered/areas[i].num,P,P2,a);
	
	fclose(output2);

	char filename3[150];
	sprintf(filename3, "%s_DATA_sub_%i_camPos_%i_mul_%i_stp_%i_2.png",  model_name.c_str(), nSub, camPos, rate, size);
	saveGLScreen(filename3);
}

void Raster::setName(char* n)
{
	std::string s(n);
	std::string name = s.substr(6,  s.find('.') - s.find('\/')-1);
	model_name = std::string("C:\/Users\/Yao\/Dropbox\/Updated\/") + name;
}